﻿using MovingChame.Web.Helpers;
using MovingChame.Web.Models;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity.Validation;
using System.Data.Spatial;
using System.Diagnostics;
using System.Linq;
using System.Web;

namespace MovingChame.Web.Infrastructure
{
    public class LocationProvider : ILocationProvider
    {
        private static LocationProvider current;
        public static LocationProvider Current
        {
            get
            {
                if (current == null)
                    current = new LocationProvider();
                return current;
            }
        }

        #region Configuration
        private string applicationName;
        public string ApplicationName
        {
            get { return applicationName; }
            set { applicationName = value; }
        }

        private string connectionStringName;
        private string providerName;
        private MovingChameModelContainer db;

        public void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            providerName = name;

            if (config["applicationName"] != null)
                applicationName = config["applicationName"];

            if (config["connectionStringName"] != null)
            {
                connectionStringName = config["connectionStringName"];
                db = new MovingChameModelContainer();
                db.Database.Connection.ConnectionString = ConfigurationHelper.GetConnectionString(connectionStringName);
            }
            else
                db = new MovingChameModelContainer();
        }

        private LocationProvider()
        {
            Initialize("LocationProvider", new System.Collections.Specialized.NameValueCollection());
        }
        #endregion

        #region Interface Methods - Add, update, remove
        public int AddLocation(string name, double longtitude, double latitude, string imagepath, string description)
        {
            DbGeography center = DbGeography.FromText("POINT(" + longtitude.ToString() + " " + latitude.ToString() + ")");
            Location location = new Location
            {
                Name = name,
                Center = center,
                ImagePath = imagepath,
                LongDescription = description
            };

            db.Locations.Add(location);
            db.SaveChanges();

            return location.Id;
        }

        public bool UpdateLocation(int locationId, Location updatedLocation)
        {
            Location location = GetLocationById(locationId);
            if (location == null)
                return false;
            db.Entry(location).CurrentValues.SetValues(updatedLocation);
            try
            {
                db.SaveChanges();
            }
            catch (Exception e)
            {
                return false;
            }
            return true;
        }

        public bool UpdateLocationDescription(int locationId, string imagepath, string description)
        {
            Location location = null;
            try
            {
                location = db.Locations.Single(o => o.Id == locationId);
            }
            catch (ArgumentNullException)
            {
                return false;
            }
            location.LongDescription = description;
            location.ImagePath = imagepath;
            db.SaveChanges();
            return true;
        }

        public void RemoveLocation(int locationId)
        {
            var location = db.Locations.SingleOrDefault(o => o.Id == locationId);
            if (location == null)
                throw new ArgumentException("Wrong Location ID", "locationId");

            db.Locations.Remove(location);
            db.SaveChanges();
        }
        #endregion

        #region Interface Methods - Get
        public Location GetLocationById(int locationId)
        {
            return db.Locations.SingleOrDefault(o => o.Id == locationId);
        }

        public IQueryable<Location> SearchLocationInName(String keyword)
        {
            return db.Locations.Where(o => o.Name.ToLower().Contains(keyword.ToLower()));
        }

        public IQueryable<Location> SearchLocationInDescription(String keyword)
        {
            return db.Locations.Where(o => o.LongDescription.ToLower().Contains(keyword.ToLower()));
        }

        public IQueryable<Location> SearchLocation(String keyword)
        {
            IQueryable<Location> result = Enumerable.Empty<Location>().AsQueryable();
            result = result.Union(SearchLocationInDescription(keyword));
            result = result.Union(SearchLocationInName(keyword));
            return result;
        }

        public IQueryable<Location> GetAllLocations()
        {
            return db.Locations;
        }
        #endregion
    }
}